<?php

namespace app\common\lib\redEnvelopes;

use app\api\model\RedEnvelopesLog as RedEnvelopesLogModel;
use app\api\model\RedEnvelopes as RedEnvelopesModel;
use app\common\service\Redis;
use app\common\exception\ParameterFailedException;
use app\common\exception\RuntimeException;
use Exception;
use think\Db;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\DbException;
use think\facade\Cache;

/**
 * 拼手气红包
 * @package app\api\service
 *
 * @Author: Li Guo Xin <guoxinlee129@gmail.com>
 * @Date: 2020/4/17
 * @Time: 22:07
 */
class LuckyRedEnvelope implements RedEnvelopes
{
    private const TYPE                    = 'lucky';
    private const MIN_RED_ENVELOPE_AMOUNT = 0.01; #红包最小值

    private $redEnvelopesModel;
    private $remainderAmount = 0;#剩余红包总金额
    private $remainderNumber = 0;#剩余红包个数

    /**
     * @param $total_amount
     * @param $number
     * @param $user_id
     * @return bool
     * @throws Exception
     *
     * @Author: Li Guo Xin <guoxinlee129@gmail.com>
     * @Date: 2020/4/27
     * @Time: 20:29
     */
    public function generate($total_amount, $number, $user_id): bool
    {
        $total_amount = filter_var($total_amount, FILTER_VALIDATE_INT);
        $number       = filter_var($number, FILTER_VALIDATE_INT);
        if ($total_amount === false || $number === false) {
            throw new ParameterFailedException(['msg' => '红包参数错误']);
        }
        //总金额(用户填写) = 单个红包的金额(缺省) * 红包个数(用户填写)
        if ($total_amount < 0.01 * $number || $total_amount > 200000) {
            throw new ParameterFailedException(['msg' => '红包参数错误']);
        }

        //$newRedEnvelopesModel = new RedEnvelopesModel();
        //$newRedEnvelopesModel->user_id = $user_id;
        //$newRedEnvelopesModel->total_amount = $total_amount;
        //$newRedEnvelopesModel->number = $number;
        //$newRedEnvelopesModel->type = $user_id;
        $preSaveData = [
            'user_id'      => $user_id,
            'total_amount' => $total_amount,
            'number'       => $number,
            'type'         => self::TYPE,
        ];

        Db::startTrans();
        try {
            $newRedEnvelopesModel = RedEnvelopesModel::create($preSaveData);
            if (!$newRedEnvelopesModel) {
                throw new RuntimeException();
            }

            Redis::getRedis()->hMSet('red_envelope_'.self::TYPE.'_'.$newRedEnvelopesModel->id, $newRedEnvelopesModel->toArray());

            Db::commit();
            return true;
        } catch (Exception $e) {
            Db::rollback();
            throw $e;
        }
    }

    /**
     * @param $red_envelopes_id
     * @param $user_id
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws ParameterFailedException
     *
     * @Author: Li Guo Xin <guoxinlee129@gmail.com>
     * @Date: 2020/4/27
     * @Time: 21:00
     */
    public function checkStock($red_envelopes_id, $user_id)
    {
        $redEnvelopesModel = RedEnvelopesModel::where('id', $red_envelopes_id)
            ->where('user_id', $user_id)
            ->where('type', self::TYPE)
            ->with(['robLog'])
            ->find();
        if (!$redEnvelopesModel) {
            throw new ParameterFailedException(['msg' => '该红包不存在']);
        }

        $redEnvelopesArray       = $redEnvelopesModel->toArray();
        $this->redEnvelopesModel = $redEnvelopesModel;
        $this->remainderAmount   = $redEnvelopesArray['total_amount'];
        $this->remainderNumber   = $redEnvelopesArray['number'];
        $redEnvelopesLogArray    = $redEnvelopesArray['rob_log']->toArray();
        foreach ($redEnvelopesLogArray as $item) {
            $this->remainderNumber--;
            $this->remainderAmount = bcsub($this->remainderAmount, $item['rob_amount'], 2);
        }
        return $this->remainderAmount > 0 && $this->remainderNumber > 0;
    }

    /**
     * @param $red_envelopes_id
     * @param $user_id
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws ParameterFailedException
     *
     * @Author: Li Guo Xin <guoxinlee129@gmail.com>
     * @Date: 2020/4/27
     * @Time: 22:35
     */
    public function rob($red_envelopes_id, $user_id)
    {
        $robResult = Lua::robLuckyRedEnvelope($red_envelopes_id, $user_id);
        var_dump($robResult);die;

        $stockStatus = $this->checkStock($red_envelopes_id, $user_id);
        if (!$stockStatus) {
            throw new ParameterFailedException(['msg' => '库存不足']);
        }
        //平均期望值 * 2
        if ($this->remainderNumber === 1) {
            $money = $this->remainderAmount;
        } else {
            $money = mt_rand(self::MIN_RED_ENVELOPE_AMOUNT * 100,
                    $this->remainderAmount / $this->remainderNumber * 2 * 100) / 100;
        }
        $money = $money < self::MIN_RED_ENVELOPE_AMOUNT ? self::MIN_RED_ENVELOPE_AMOUNT : $money;

        //存入红包日志表
        $redEnvelopesLogModel                   = new RedEnvelopesLogModel();
        $redEnvelopesLogModel->red_envelopes_id = $red_envelopes_id;
        $redEnvelopesLogModel->user_id          = $user_id;
        $redEnvelopesLogModel->rob_amount       = $money;
        $redEnvelopesLogModel->save();
    }
}